package com.zwh.common.utils.file;

import com.zwh.common.exception.OperationException;
import com.zwh.common.spring.SpringContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;

public class SpringUploadUtils {
    private static final Logger logger = LoggerFactory.getLogger(SpringUploadUtils.class);

    /**
     * 静态内部类，延迟加载，懒汉式，线程安全的单例模式
     */
    private static final class Static {
        private static UploadProperties uploadProperties = SpringContextUtils.getBean(UploadProperties.class);
    }

    /**
     * 不额外保存外键
     * 超过3M图片进行压缩处理
     *
     * @param request
     * @return
     * @throws OperationException
     */
    public static SpringUploadUtils.UploadDto uploadOneFile(HttpServletRequest request, String relativeDir) throws OperationException, FileNotFoundException {
        //文件根目录
        String baseDirPath = SpringUploadUtils.Static.uploadProperties.getBaseDir();
        //以当前日期天为保存相对目录
        //增加日期目录20190604
//        String relativeDir = "public/file/";
        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
        relativeDir = relativeDir + date.substring(0, 8) + "/";
        List<SpringUploadUtils.UploadDto> list = SpringUploadUtils.uploadForDir(request, relativeDir);
        if (list == null || list.isEmpty()) {
            throw new OperationException("未上传成功,请检查文件是否存在");
        }


//        String path = ResourceUtils.getURL("classpath:").getPath();
//        File rootFile = new File(path);
//        String baseDirPath =rootFile.getAbsolutePath();
        //格式可为word、PDF、JPG、PN G
        String[] limit = new String[]{".jpg", ".jpeg", ".png"};
        String typeStr = Arrays.toString(limit);
        /*if ( list.size() == 0) {
            throw new OperationException("上传失败,请检查文件是否存在");
        }


        boolean isPass = false;

        for (String suffix : limit) {
            if (fileSuffix != null && suffix.equalsIgnoreCase(fileSuffix)) {
                isPass = true;
            }
        }*/

        //不限制上传文件的格式，全部允许通过
        boolean isPass = true;
        SpringUploadUtils.UploadDto fileItem = list.get(0);
        //默认最大文件上传大小为50MB
        if (fileItem.getFileSize() > 52428800) {
            throw new OperationException("上传失败,单个文件大小不能大于50MB");
        }

        return fileItem;
    }

    /**
     * 删除的fileUrl要满足：
     * fileUrl = Global.USERFILES_BASE_URL+serverDir+file.getOriginalFilename()
     *
     * @param fileUrl
     * @return
     */
    public static boolean deleteForFileUrl(String fileUrl) {
        String baseDirPath = SpringUploadUtils.Static.uploadProperties.getBaseDir();

        if (fileUrl.startsWith("/userfiles/")) {
            fileUrl = fileUrl.replace("/userfiles/", "");
        }
        String filePhysicalPath = MessageFormat.format("{0}{1}", baseDirPath, fileUrl);
        File dFile = new File(filePhysicalPath);
        if (dFile.exists()) {
            dFile.delete();
        } else {
            return false;
        }
        return true;
    }


    /**
     * 默认设置重命名策略
     *
     * @param request
     * @param relativeDir
     * @return
     * @throws FileNotFoundException
     */
    public static List<SpringUploadUtils.UploadDto> uploadForDir(HttpServletRequest request, String relativeDir) throws FileNotFoundException {
        return SpringUploadUtils.uploadForDir(request, relativeDir, false);
    }

    /**
     * 保存上传的文件到给定的相对目录下，返回文件列表
     * TODO 文件上传限制（文件大小，文件类型，文件重命名等策略待补充）
     * @param request
     * @param relativeDir  文件要保存的相对路径 如 file/image/
     * @param renamePolicy
     * @return
     * @throws FileNotFoundException
     */
    public static List<SpringUploadUtils.UploadDto> uploadForDir(HttpServletRequest request, String relativeDir, boolean renamePolicy) throws FileNotFoundException {
        List<SpringUploadUtils.UploadDto> uploadDtos = new ArrayList<>();
        String baseDirPath = SpringUploadUtils.Static.uploadProperties.getBaseDir();

        // 使用Jakarta Commons FileUpload解析multipart请求
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
        multipartResolver.setDefaultEncoding(
                SpringUploadUtils.Static.uploadProperties.getHeaderEncoding() == null ? "UTF-8" :
                        SpringUploadUtils.Static.uploadProperties.getHeaderEncoding());
        if (SpringUploadUtils.Static.uploadProperties.getTempPath() != null) {
            try {
                multipartResolver.setUploadTempDir(new FileSystemResource(SpringUploadUtils.Static.uploadProperties.getTempPath()));
            } catch (IOException e) {
                logger.error("设置上传文件临时目录错误:sys.common.upload.tempPath:" + SpringUploadUtils.Static.uploadProperties.getTempPath());
                e.printStackTrace();
            }
        }
        if (multipartResolver.isMultipart(request)) {
            MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
            Iterator iter = multiRequest.getFileNames();

            while (iter.hasNext()) {
                //这里上传的文件会到临时目录，需要创建一个文件地址来接收临时目录数据
                List<MultipartFile> files = multiRequest.getFiles(iter.next().toString());
                for (MultipartFile file : files) {
                    SpringUploadUtils.UploadDto uploadDto = saveFile(file, baseDirPath, relativeDir, renamePolicy);
                    if (uploadDto != null) {
                        uploadDtos.add(uploadDto);
                    }
                }
            }
        }
        return uploadDtos;
    }

    public static SpringUploadUtils.UploadDto saveFile(MultipartFile file, String baseDirPath, String relativeDir, boolean renamePolicy) {
        if (file != null) {
            String dirPath = MessageFormat.format("{0}{1}", baseDirPath, relativeDir);
            String finalPath = dirPath + file.getOriginalFilename();//重命名文件名，以年月日时分秒作为前缀，避免外部重新命名文件
            File rFile = new File(finalPath);
            if (!rFile.getParentFile().exists()) {
                rFile.getParentFile().mkdirs();
            }
            if (renamePolicy) {
                // 使用文件命名策略，如果该目录下存在相同文件名，调用命名策略
                MyFileNamePolicy policy = new MyFileNamePolicy();
                File tmpFile = new File(finalPath);
                tmpFile = policy.rename(tmpFile);
                finalPath = dirPath + tmpFile.getName();
                rFile = new File(finalPath);
            }

            try {
                //使用此方法保存必须要绝对路径且文件夹必须已存在,否则报错
                file.transferTo(rFile);
            } catch (IOException var12) {
                logger.error("传送文件失败..", var12);
            }
            //获取真实路径的文件名
            String fileName = finalPath.substring(dirPath.length());//file.getOriginalFilename();
            String fileSuffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
            //保存路径默认会添加"/userfiles/"前缀，文件路径需要补上
            return new SpringUploadUtils.UploadDto(fileName,
                    MessageFormat.format("{0}{1}", relativeDir, fileName),
                    file.getSize(),
                    fileSuffix);
        }
        return null;
    }

    public static class UploadDto {
        private String fileName;
        private String fileUrl;
        private Long fileSize;
        private String fileSuffix;

        public String getFileName() {
            return this.fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public String getFileUrl() {
            return this.fileUrl;
        }

        public void setFileUrl(String fileUrl) {
            this.fileUrl = fileUrl;
        }

        public Long getFileSize() {
            return this.fileSize;
        }

        public void setFileSize(Long fileSize) {
            this.fileSize = fileSize;
        }

        public String getFileSuffix() {
            return this.fileSuffix;
        }

        public void setFileSuffix(String fileSuffix) {
            this.fileSuffix = fileSuffix;
        }

        public UploadDto(String fileName, String fileUrl, Long fileSize, String fileSuffix) {
            this.fileName = fileName;
            this.fileUrl = fileUrl;
            this.fileSize = fileSize;
            this.fileSuffix = fileSuffix;
        }

        public UploadDto(String fileUrl) {
            this.fileUrl = fileUrl;
        }

        public UploadDto() {
        }
    }
}
